using System;
using System.Collections;
using System.Collections.Generic;
using Entitas;
using Entitas.Unity;
using UnityEngine;
using Random = UnityEngine.Random;

public static class LogicApi
{
    public static void CreateCell(LogicContext context, int hp, int color, GridPosition pos, int createFrame)
    {
        if (!TryGetGrid(context, pos.Row, pos.Column, out var grid)) return;
        grid.ReplaceCreateCell(createFrame, 0, hp, color, pos);
    }
    
    public static LogicEntity CreateCell(LogicContext context, int hp, int color, Vector3 pos, LogicEntity grid)
    {
        LogicEntity e = context.CreateEntity();
        e.isCell = true;
        e.ReplaceHp(hp);
        e.ReplaceCellColor(color);
        e.ReplaceGridPos(pos);
        e.ReplacePosition(pos);
        e.ReplaceResourceInfo($"normal_{color.ToString()}");
        grid.grid.CellLst.Add(e);
        return e;
    }

    public static void DestroyCell(LogicContext context, LogicEntity cell)
    {
        TryGetGrid(context, cell.gridPos.Value.Row, cell.gridPos.Value.Column, out var grid);
        grid.grid.CellLst.Remove(cell);
        
        cell.logicView.Go.Unlink();
        MatchObjectPool.Instance.DespawnCellView(cell.logicView.View);
        GameObjectPool.Instance.DespawnGo(cell.resourceInfo.AssetName, cell.logicView.Go);
        cell.ReplaceLogicView(null, null);
    }
    
    public static LogicEntity CreateGrid(LogicContext context, GridPosition pos)
    {
        LogicEntity e = context.CreateEntity();
        e.ReplaceGrid(new List<LogicEntity>());
        e.ReplaceGridPos(pos);
        e.ReplacePosition(pos);
        e.ReplaceResourceInfo("grid");
        return e;
    }

    public static LogicEntity CreateBoard(LogicContext context, int row, int col)
    {
        LogicEntity e = context.CreateEntity();
        e.ReplaceBoard(new LogicEntity[row,col]);
        var grids = e.board.Grids;
        for (int r = 0; r < row; r++)
        {
            for (int c = 0; c < col; c++)
            {
                GridPosition gPos = new GridPosition(r, c);
                grids[r,c] = CreateGrid(context, gPos);
                CreateCell(context, 1, Random.Range(1, 6), gPos, Time2Frame(0));
            }
        }

        return null;
    }

    public static void ResetBoard(LogicContext context, int row, int col)
    {
        var grids = context.boardEntity.board.Grids;
        for (int r = 0; r < row; r++)
        {
            for (int c = 0; c < col; c++)
            {
                var grid = grids[r, c];
                foreach (var cell in grid.grid.CellLst)
                    cell.AddDestroyCell(0,0);
            }
        }
        
        for (int r = 0; r < row; r++)
        {
            for (int c = 0; c < col; c++)
            {
                var grid = grids[r, c];
                CreateCell(context, 1, Random.Range(1, 6), grid.gridPos.Value, Time2Frame(0));
            }
        }
    }

    public static void ProfilerSample(string name, Action func)
    {
        UnityEngine.Profiling.Profiler.BeginSample(name);
        func.Invoke();
        UnityEngine.Profiling.Profiler.EndSample();
    }

    public static bool TryGetGrid(LogicContext context, int row, int col, out LogicEntity grid)
    {
        grid = null;
        var grids = context.boardEntity.board.Grids;
        if (row < 0 || row > grids.GetLength(0) || col < 0 || col > grids.GetLength(1)) return false;
        grid = grids[row, col];
        return grid != null;
    }
    
    public static LogicEntity GetGridEntityByMousePos(LogicContext context, Vector3 mousePos)
    {
        Vector3 mousePoint = Camera.main.ScreenToWorldPoint(mousePos);
        if (mousePoint.x <= -0.5f || mousePoint.x >= 8.5f || mousePoint.y <= -0.5f || mousePoint.y >= 8.5f) return null;
        int row = Mathf.FloorToInt((mousePoint.x - (-0.5f))/1f);
        int col = Mathf.FloorToInt((mousePoint.y - (-0.5f))/1f);
        if (!TryGetGrid(context, row, col, out var grid))
            return null;
        return grid;
    }

    public static int Time2Frame(float time)
    {
        return Mathf.RoundToInt(time * EcsManager.LogicFrame);
    }
}
